# -*- coding: utf-8 -*-

import psi, psi.process
import os
import re
import sys
import math
import time
import traceback
import smtplib
import datetime
import pprint
import gc
import simplejson as json
import logging
import rrdtool
from threading import Thread, Timer
from Cheetah.Template import Template
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders

dashboard_report = '/var/www/mvc/widget/res/dashboard_report.json'
intervalTimer = 2
gmail_user = "monitor@mana.vn"
gmail_pwd = "monitor@)!!"
logging.basicConfig()
logger= logging.getLogger('dashboard')
logger.setLevel(logging.DEBUG)
st = int(time.time()) - intervalTimer
rrdDb = 'dashboard.rrd'
if not os.path.isfile(rrdDb):
    rrdtool.create(rrdDb, 
       '--start', str(st),
       '--step', str(intervalTimer),
       'DS:memstat:GAUGE:600:U:U',
       'DS:cpustat:GAUGE:600:U:U',
       'RRA:AVERAGE:0.5:3:24',
       'RRA:AVERAGE:0.5:6:10')

def getProcess(services=None):
    print 'call getProcess'
    listProcesses = []
    try:
        print "There are {0} processes".format(len(psi.process.ProcessTable()))
        for p in psi.process.ProcessTable().values():
            try:
                cmdLine = ' '.join(p.args).strip()
            except psi.AttrInsufficientPrivsError, e:
                cmdLine = str(e)
            if services != None:
                for s in services.values():
                    if ((s != p.name) or (re.search(s, cmdLine) == None)): continue 
            all_status = [(s, getattr(psi.process, s)) for s in dir(psi.process)
                          if s.startswith('PROC_STATUS_')]
            proc_status = [s[0] for s in all_status if p.status == s[1]]
            _1m = 1024*1024
            pstatus = ', '.join(proc_status)
            listProcesses.append({'pid': int(p.pid), 'name': p.name, 'exe': getattr(p, 'exe', 'N/A'),
                    'cmdLine': cmdLine, 'status': int(p.status), 'statusName': pstatus, 'memUse': str(math.ceil(p.rss/_1m))})
        print 'finished getProcess'
    except:
        traceback.print_exc()
    return listProcesses

def getCpu():
    a = os.popen("iostat").read()
    cbreak = False
    cpu = 'U'
    for line in a.splitlines():
        if cbreak:
            m = re.search('([0-9\.]+)', line)
            if m: cpu = m.group(1)
            break
        if line.startswith('avg-cpu'): cbreak = True
    return float(cpu)
            
def memoryStatistic():
    memoryInfo = {'total': '', 'used': '', 'free': ''}
    try:
        m = re.findall('(\d+)', os.popen("free -m | grep Mem").read())
        if m: 
            memoryInfo['total'] = long(m[0])
            memoryInfo['used'] = long(m[1])
            memoryInfo['free'] = long(m[2])
    except:
        traceback.print_exc()
    finally:
        return memoryInfo

def mail(to, subject, text, attach=None):
    ''' Dùng Gmail để gửi thông tin alert đi'''
    print 'call mail({0}, {1}, {2})'.format(to, subject, text)
    try:
        msg = MIMEMultipart()
        msg['From'] = gmail_user
        msg['To'] = to
        msg['Subject'] = subject
        msg.attach(MIMEText(text))
        if attach != None:
           part = MIMEBase('application', 'octet-stream')
           part.set_payload(open(attach, 'rb').read())
           Encoders.encode_base64(part)
           part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(attach))
           msg.attach(part)
        mailServer = smtplib.SMTP("smtp.gmail.com", 587)
        mailServer.ehlo()
        mailServer.starttls()
        mailServer.ehlo()
        mailServer.login(gmail_user, gmail_pwd)
        mailServer.sendmail(gmail_user, to, msg.as_string())
        mailServer.close()
    except:
        traceback.print_exc()

def dumpJson(file, obj):
    try:
        fp = open(file, 'w')
        json.dump(obj, fp)
        fp.close()
        return True
    except:
        return False

def doCheck(services):
    print 'call doCheck'
    listProcesses = getProcess(services)
    checkedService = {}
    for name, s in services.items(): checkedService[s] = checkedService[s] = {'desc': name, 'result': False, 'pid': 'N/A', 'name': s, 'cmdLine': '', 
                    'statusName': 'Not Found', 'status': '', 'memUse': ''}
    for p in listProcesses:
        c = 0
        for s, v in checkedService.items():
            if v['result']: continue
            c += 1
            if re.search("({0}\s)|({0}$)".format(s), p['cmdLine']):
                if p['status'] in [0, 1]:
                    checkedService[s]['result'] = True
                else:
                    checkedService[s]['result'] = False
                checkedService[s]['pid'] = p['pid']
                checkedService[s]['name'] = p['name']
                checkedService[s]['cmdLine'] = p['cmdLine']
                checkedService[s]['statusName'] = p['statusName']
                checkedService[s]['status'] = p['status']
                checkedService[s]['memUse'] = p['memUse']
        if c==0: break
    memInfo = memoryStatistic()
    ctime = int(time.time())
    rrdtool.update(rrdDb, "--template", "memstat:cpustat", "%d:%d:%f" % (ctime, memInfo['free'], getCpu()))
#    rrdtool.update('memory.rrd', "--template", "cpustat", "%d:%d" % (ctime, int(getCpu())))
    _avg = psi.loadavg()
    loadAvg = '({0}, {1}, {2})'.format(round(_avg[0], 2), round(_avg[1], 2), round(_avg[2], 2))
    searchList = {'checkedService': checkedService, 'memInfo': memInfo, 'loadAverage': loadAvg, 'time': datetime.datetime.now().strftime("%H:%M:%S %d/%m/%Y")}
    dumpJson(dashboard_report, searchList)
    Timer(intervalTimer, doCheck, args=[services]).start()
    
def ve(filename, dsName, info={}):
    print 'call ve'
    print locals()
    start_time = int(time.time()) - 720
    rrdtool.graph(filename,
                  '--start', str(start_time),
                  '--end', str(start_time + 864),
                  '--vertical-label', info['vertical-label'],
                  '--imgformat', 'PNG',
                  '--title', info['title'],
                  '--lower-limit', '0',
                  'DEF:data={0}:{1}:AVERAGE'.format(rrdDb, dsName),
                  'LINE1:data#FF0000')  
    Timer(intervalTimer, ve, args=(filename, dsName, info)).start()        

def totimestamp(_time):
    tple = datetime.datetime.timetuple(_time)
    return time.mktime(tple)

if __name__ == '__main__':
    checks = {'Apache service': 'httpd', 
              'Sphinx searchd': 'searchd', 
              'MySQL': 'mysqld', 
              'MongoDB': 'mongod', 
              'beanstalkd': 'beanstalkd',
              'crond': 'crond', 
              'Front end server': 'python.+ server.py', 
              'Restart worker service': 'python.+restart-service.py',
              'Module Tien len': 'python.+worker.py.+tienlenmn.py',
              'Module Tai game': 'python.+worker.py.+taigame.py',
              'Module Rao vat': 'python.+worker.py.+raovat.py',
              'Module Mail': 'python.+worker.py.+mail.py',
              'Mana News': 'python.+worker.+partner.py',
              'Cac module trong Cfg1.py': 'python.+worker.py.+cfg1.py'
              }
    
    Thread(target=doCheck, args=[checks]).start()
    Thread(target=ve, args=('memory.png', 'memstat', {'vertical-label': 'Memory (MB)', 'title': 'Time'})).start()
    Thread(target=ve, args=('cpu.png', 'cpustat', {'vertical-label': 'CPU (%)', 'title': 'Time'})).start()
#    print 'Start at {0}'.format(datetime.datetime.now())
#    Thread(target=doCheck, args=[checks]).start()
#    rrdOutput()
#    print 'Total gc collected: ', gc.collect()
#    del gc.garbage[:]
#    print 'Total obj gc not garbage: ', gc.collect()
#    print 'Finished at {0}'.format(datetime.datetime.now())
#    os._exit(1)
    
    